expect配合shell 实现自动分发秘钥文件

expect

Expect是一个用来处理交互的命令。它可以模拟键盘输入文本,省去人工干预交互式的指令。

整体来说大致的流程包括:

    运行程序
    程序要求人的判断和输入
    Expect 通过关键字匹配
    根据关键字向程序发送符合的字符串

代码例子如下:在Shell中引用expect,自动登陆ssh localhost,自动回复yes回车继续执行。
1
2
3
4
5
6
7
8
9
#!/bin/bash
/usr/bin/expect >/dev/null 2>&1 <<EOF
set time 30
spawn ssh localhost
expect "*yes/no"
send "yes\r"
send "exit 1\r"
expect eof
EOF

Expect解析

Expect中最关键的四个命令是send,expect,spawn,interact。

spawn:     spawm命令就是用来启动新的进程的。spawn后的send和expect命令都是和spawn打开的进程进行交互的。
expect:    从进程接收字符串,监听作用
send:      用于向进程发送字符串,回复作用
interact:  允许用户在适当的位置进行交互

expect命令和send命令正好相反,expect通常是用来等待一个进程的反馈。

expect可以接收一个字符串参数,也可以接收正则表达式参数。

expect脚本必须以interact或expect eof结束,执行自动化任务通常expect eof就够了


需要注意的是:

expect执行完毕后,想退出执行环境,可以向进程发送"exit 1\r"退出环境,重新回到bash执行环境。

Expect-模式动作

expect可以写成独立的格式,脚本格式为,如:

#!/usr/bin/expect

也可以嵌套在shell脚本中使用

expect 使用 ‘{ }’表示一组表达式,且花括号前后要留空格

例如:

expect "(yes/no)" {send "yes\n"}
## "(yes/no)"   是期望匹配的字符串
## { send "yes\n"; exp_continue } expect 匹配到字符串后执行模拟输入的内容

expect还可以使用多字符匹配:如下

expect {
    "(yes/no)" { send "yes\n"; exp_continue }
    "password:" { send "$password\n" }
}

单一分支模式:

## 匹配到"hi",进程自动回复"you said hi"

expect "hi" { send "You said hi" }

多个分支模式:

## 匹配到hi,hello,bye任意一个字符串时,执行相应的输出

expect "hi" { send "You said hi\n" } \
"hello" { send "Hello yourself\n" } \
"bye" { send "That was unexpected\n" }

等同于如下写法:

expect {
"hi" { send "You said hi\n"}
"hello" { send "Hello yourself\n"}
"bye" { send "That was unexpected\n"}
}

interact

interact作用是在一键安装的时候,可以让人为干预一键安装过程。

比如下载完ftp文件时,仍然可以停留在ftp命令行状态,以便手动的执行后续命令。

interact可以达到这些目的。下面的demo在自动登录ftp后,允许用户交互。代码如下:
1
2
3
4
5
6
spawn ftp ftp.test.com
expect "Name"
send "user\r"
expect "Password:"
send "123456\r"
interact

expect工作方式

首先使用 spawn 开启一个会话,然后使用 expect-send 对来执行交互式操作。

spawn 后面跟上一个命令操作,表示开启一个会话。

expect 等待输出特定的字符串(通常是提示符),然后使用send 发送交互字符串。
1
2
3
4
5

password=123456
spawn ssh username@host # 远程登录
expect "*assword" # 提示为:"username@host's password:", 等待用户输入密码
send "${password}\r" # 这时使用send模拟用户输入密码的字符串,完成登录验证

安装

yum install expect -y

实例:自动推送秘钥文件到远程主机

试想,如果要实现一些自动化的工作时,免密远程登录是必不可少的,
(使用ansible的authoried_keys模块的方式推送就另说了)

假如在部署ansible前要将ansible的秘钥文件推送给100台服务器,
这个时候在脚本中使用scp指令避免不了要进行交互式地应答,
这个时候就需要使用expect来进行自动应答地执行了
编写shell脚本,在脚本中调用expect来实现自动向远处主机推送秘钥:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

#!/bin/bash

keypath=/root/.ssh
[ -d ${keypath} ] || mkdir -p ${keypath}
rpm -q expect &> /dev/null || yum install expect -y
ssh-keygen -t rsa -f /root/.ssh/id_rsa -P ""
password=fsz...

while read ip;do

expect <<EOF
set timeout 5
spawn ssh-copy-id $ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
expect eof
EOF

done < /home/iplist.txt
1
2
3
4
5
6
7
8

cat > /home/iplist.txt
192.168.214.148
192.168.214.143
192.168.214.133
192.168.214.135
192.168.214.139
192.168.214.134

参考

https://www.cnblogs.com/anay/p/9059548.html